"""FastAPI 应用主文件"""
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from app.config import settings
from app.models.model_manager import model_manager
from app.schemas.requests import (
    TextInput,
    TextPairInput,
    ClassificationResponse,
    SimilarityResponse,
    NERResponse,
    HealthResponse,
    ErrorResponse
)
from app.services.classification import classify_text_service
from app.services.similarity import calculate_similarity_service
from app.services.ner import extract_entities_service
from app.services.search.search_orchestrator import SearchOrchestrator
from app.services.search.storage_service import StorageService
from app.services.search.background_task import background_task_service
from app.schemas.requests import (
    SearchRequest,
    SearchResponse,
    QuestionListResponse,
    QuestionDetailResponse
)
from app.database.connection import init_database, check_database_connection
from typing import Optional
import asyncio

# 配置日志
logging.basicConfig(
    level=getattr(logging, settings.LOG_LEVEL),
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    # 启动时初始化模型
    logger.info("应用启动，开始初始化模型...")
    try:
        model_manager.initialize_models()
        logger.info("模型初始化完成")
    except Exception as e:
        logger.error(f"模型初始化失败: {str(e)}", exc_info=True)
        raise
    
    # 初始化数据库
    logger.info("检查数据库连接...")
    try:
        if check_database_connection():
            init_database()
            logger.info("数据库初始化完成")
            
            # 启动后台任务
            try:
                background_task_service.start()
                logger.info("后台任务已启动")
            except Exception as e:
                logger.warning(f"后台任务启动失败: {str(e)}")
        else:
            logger.warning("数据库连接失败，部分功能可能不可用")
    except Exception as e:
        logger.warning(f"数据库初始化失败: {str(e)}")
    
    yield
    
    # 关闭时清理资源
    logger.info("应用关闭，清理资源...")
    try:
        background_task_service.stop()
    except Exception as e:
        logger.warning(f"停止后台任务失败: {str(e)}")


# 创建 FastAPI 应用
app = FastAPI(
    title=settings.API_TITLE,
    version=settings.API_VERSION,
    description="基于 LegalBERT 的 AI 服务，提供文本分类、相似度计算和命名实体识别功能",
    lifespan=lifespan
)

# 配置 CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# 全局异常处理
@app.exception_handler(Exception)
async def global_exception_handler(request, exc):
    """全局异常处理器"""
    logger.error(f"未处理的异常: {str(exc)}", exc_info=True)
    return JSONResponse(
        status_code=500,
        content={"error": "内部服务器错误", "detail": str(exc)}
    )


# 健康检查端点
@app.get("/health", response_model=HealthResponse, tags=["健康检查"])
async def health_check():
    """健康检查端点"""
    return HealthResponse(
        status="healthy",
        message="服务运行正常"
    )


# 文本分类端点
@app.post(
    "/api/v1/classify",
    response_model=ClassificationResponse,
    tags=["文本分类"],
    summary="文本分类",
    description="对输入的法律文本进行分类"
)
async def classify(input_data: TextInput):
    """
    文本分类接口
    
    - **text**: 需要分类的文本
    """
    try:
        result = await classify_text_service(input_data.text)
        return result
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"分类请求处理失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail="服务器内部错误")


# 文本相似度端点
@app.post(
    "/api/v1/similarity",
    response_model=SimilarityResponse,
    tags=["文本相似度"],
    summary="文本相似度",
    description="计算两个法律文本之间的相似度"
)
async def similarity(input_data: TextPairInput):
    """
    文本相似度接口
    
    - **text1**: 第一个文本
    - **text2**: 第二个文本
    """
    try:
        result = await calculate_similarity_service(input_data.text1, input_data.text2)
        return result
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"相似度计算请求处理失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail="服务器内部错误")


# 命名实体识别端点
@app.post(
    "/api/v1/ner",
    response_model=NERResponse,
    tags=["命名实体识别"],
    summary="命名实体识别",
    description="识别法律文本中的命名实体（法条、案例、机构等）"
)
async def ner(input_data: TextInput):
    """
    命名实体识别接口
    
    - **text**: 需要识别实体的文本
    """
    try:
        result = await extract_entities_service(input_data.text)
        return result
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"NER 请求处理失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail="服务器内部错误")


# 搜索和存储相关端点
search_orchestrator = SearchOrchestrator()
storage_service = StorageService()


@app.post(
    "/api/v1/search/questions",
    response_model=SearchResponse,
    tags=["真题搜索"],
    summary="搜索法考真题",
    description="联网搜索全国5年法考真题并保存到数据库"
)
async def search_exam_questions(request: SearchRequest):
    """
    搜索法考真题接口
    
    - **years**: 年份列表，如 [2019, 2020, 2021, 2022, 2023, 2024]
    - **subjects**: 科目列表，如 ['民法', '刑法']
    - **max_results**: 最大搜索结果数
    """
    try:
        # 创建搜索记录
        year_range = f"{min(request.years) if request.years else 2019}-{max(request.years) if request.years else 2024}"
        search_record = storage_service.create_search_record(
            search_query=f"法考真题 {year_range}",
            search_type="both",
            year_range=year_range
        )
        
        # 异步执行搜索（不阻塞请求）
        asyncio.create_task(
            search_orchestrator.search_and_save_questions(
                years=request.years,
                subjects=request.subjects,
                search_record_id=search_record.id
            )
        )
        
        return SearchResponse(
            search_id=search_record.id,
            status="running",
            message="搜索任务已启动，正在后台执行",
            total_found=0,
            total_saved=0
        )
    except Exception as e:
        logger.error(f"启动搜索任务失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"启动搜索任务失败: {str(e)}")


@app.get(
    "/api/v1/questions",
    response_model=QuestionListResponse,
    tags=["真题查询"],
    summary="查询题目列表",
    description="根据条件查询题目列表"
)
async def get_questions(
    year: Optional[int] = None,
    subject: Optional[str] = None,
    limit: int = 100
):
    """
    查询题目列表接口
    
    - **year**: 年份过滤
    - **subject**: 科目过滤
    - **limit**: 返回数量限制
    """
    try:
        if year:
            questions = storage_service.get_questions_by_year(year, limit=limit)
        elif subject:
            questions = storage_service.get_questions_by_subject(subject, limit=limit)
        else:
            # 返回所有题目（需要添加通用查询方法）
            questions = []
        
        questions_data = []
        for q in questions:
            questions_data.append({
                "question_id": q.question_id,
                "content": q.content[:200] + "..." if len(q.content) > 200 else q.content,
                "subject": q.subject,
                "year": q.year,
                "difficulty": q.difficulty,
                "source_url": q.source_url
            })
        
        return QuestionListResponse(
            total=len(questions_data),
            questions=questions_data
        )
    except Exception as e:
        logger.error(f"查询题目列表失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"查询失败: {str(e)}")


@app.get(
    "/api/v1/questions/{question_id}",
    response_model=QuestionDetailResponse,
    tags=["真题查询"],
    summary="查询题目详情",
    description="根据题目ID查询题目详情"
)
async def get_question_detail(question_id: str):
    """
    查询题目详情接口
    
    - **question_id**: 题目ID
    """
    try:
        question = storage_service.get_question_by_id(question_id)
        if not question:
            raise HTTPException(status_code=404, detail="题目不存在")
        
        return QuestionDetailResponse(
            question_id=question.question_id,
            content=question.content,
            question_type=question.question_type,
            options=question.options,
            correct_answer=question.correct_answer,
            explanation=question.explanation,
            subject=question.subject,
            category=question.category,
            difficulty=question.difficulty,
            knowledge_points=question.knowledge_points,
            year=question.year,
            source_url=question.source_url,
            entities=question.entities,
            classification=question.classification
        )
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"查询题目详情失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"查询失败: {str(e)}")


# 根路径
@app.get("/", tags=["根路径"])
async def root():
    """根路径"""
    return {
        "message": "LegalBERT AI Service",
        "version": settings.API_VERSION,
        "docs": "/docs",
        "health": "/health"
    }


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "app.main:app",
        host=settings.API_HOST,
        port=settings.API_PORT,
        reload=True
    )

